package top.guochenchen.mydb.backend.dm.page;

import java.util.Arrays;

import top.guochenchen.mydb.backend.dm.pageCache.PageCache;
import top.guochenchen.mydb.backend.utils.Parser;

/**
 * PageX管理普通页
 * 普通页结构
 * [FreeSpaceOffset] [Data]
 * FreeSpaceOffset: 2字节 空闲位置开始偏移
 * 页面结构：[FreeSpaceOffset: 2字节] [Data: 剩余空间]
 * 核心概念：
 * FSO (Free Space Offset)：2字节无符号数，记录空闲位置偏移
 * 数据存储：从第2字节开始存储实际数据
 * 空间管理：通过 FSO 管理页内空闲空间
 */
public class PageX {
    private static final short OF_FREE = 0;      // 空闲偏移字段位置
    private static final short OF_DATA = 2;      // 数据起始位置
    public static final int MAX_FREE_SPACE = PageCache.PAGE_SIZE - OF_DATA; // 最大可用空间

    public static byte[] initRaw() {             // 初始化普通页
        byte[] raw = new byte[PageCache.PAGE_SIZE];
        setFSO(raw, OF_DATA);                    // 设置初始FSO为2
        return raw;
    }

    private static void setFSO(byte[] raw, short ofData) { // 设置FSO
        System.arraycopy(Parser.short2Byte(ofData), 0, raw, OF_FREE, OF_DATA);
    }

    // 获取pg的FSO
    public static short getFSO(Page pg) {
        return getFSO(pg.getData());
    }

    private static short getFSO(byte[] raw) {
        return Parser.parseShort(Arrays.copyOfRange(raw, 0, 2));
    }

    // 将raw插入pg中，返回插入位置
    public static short insert(Page pg, byte[] raw) {
        pg.setDirty(true);                       // 标记为脏页
        short offset = getFSO(pg.getData());     // 获取当前空闲偏移
        System.arraycopy(raw, 0, pg.getData(), offset, raw.length); // 复制数据
        setFSO(pg.getData(), (short)(offset + raw.length)); // 更新FSO
        return offset;                           // 返回插入位置
    }

    // 获取页面的空闲空间大小
    public static int getFreeSpace(Page pg) {
        return PageCache.PAGE_SIZE - (int)getFSO(pg.getData());
    }

    // 将raw插入pg中的offset位置，并将pg的offset设置为较大的offset
    public static void recoverInsert(Page pg, byte[] raw, short offset) {
        pg.setDirty(true);
        System.arraycopy(raw, 0, pg.getData(), offset, raw.length);

        short rawFSO = getFSO(pg.getData());
        if(rawFSO < offset + raw.length) {
            setFSO(pg.getData(), (short)(offset+raw.length));
        }
    }

    // 将raw插入pg中的offset位置，不更新update
    public static void recoverUpdate(Page pg, byte[] raw, short offset) {
        pg.setDirty(true);
        System.arraycopy(raw, 0, pg.getData(), offset, raw.length);
    }
}
